package suncertify.view.client;

import suncertify.service.ServiceFactory;
import suncertify.service.Service;
import suncertify.service.ServiceEvent;
import suncertify.view.AsyncActionListener;
import suncertify.view.SwingUtils;
import suncertify.view.SCButton;
import suncertify.util.Notification;
import suncertify.util.Messages;

import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import java.util.Observer;
import java.util.Observable;
import java.awt.*;
import java.awt.event.*;

/**
 * Implementation of client main frame. Contains
 * buttons set and table for displaying data
 */
public class ClientWindow extends JFrame implements Observer, ListSelectionListener {
    private static final Messages msg = Messages.getInstance();
    private static final Dimension dim = new Dimension(740, 480);
    private static final Dimension minSize = new Dimension(600, 400);
    private DBTable table;
    private RowDialog rowDialog;
    private OptionsDialog optDialog;
    private JButton createButton;
    private JButton editButton;
    private JButton deleteButton;
    private JButton showAllButton;
    private JButton findButton;
    private JButton reconnectButton;
    private JButton optionsButton;
    private Service service;

    /**
     * constructor
     */
    public ClientWindow() {
        super(msg.get("ui.client.title"));
        setMinimumSize(minSize);
        initComponents();
    }

    private void enable(Component... components) {
        for (Component c : components) {
            c.setEnabled(true);
        }
    }

    private void disable(Component... components) {
        for (Component c : components) {
            c.setEnabled(false);
        }
    }

    private void initComponents() {
        service = ServiceFactory.getInstance().getService();
        
        createButton = new SCButton(msg.get("ui.client.button.create"));
        editButton = new SCButton(msg.get("ui.client.button.edit"));
        deleteButton = new SCButton(msg.get("ui.client.button.delete"));
        showAllButton = new SCButton(msg.get("ui.client.button.show.all"));
        findButton = new SCButton(msg.get("ui.client.button.find"));
        reconnectButton = new SCButton(msg.get("ui.client.button.reconnect"));
        optionsButton = new SCButton(msg.get("ui.client.button.options"));

        optDialog = new OptionsDialog(this);
        rowDialog = new RowDialog(service, this);


        disable(createButton, deleteButton, showAllButton, findButton, editButton);

        deleteButton.addActionListener(new AsyncActionListener() {
            public void doAsync(ActionEvent event) {
                deleteRecord();
            }
        });

        createButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                rowDialog.create();
            }
        });

        editButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                editRecord();
            }
        });

        findButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                rowDialog.find();
            }
        });
        showAllButton.addActionListener(new AsyncActionListener() {
            public void doAsync(ActionEvent event) {
                service.search(null);
                table.refresh();
            }
        });

        reconnectButton.addActionListener(new AsyncActionListener() {
            public void doAsync(ActionEvent actionEvent) {
                service.init();
            }
        });

        optionsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                optDialog.setVisible(true);
            }
        });


        service.addObserver(this);
        table = new DBTable(service);
        table.getSelectionModel().addListSelectionListener(this);
        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent mouseEvent) {
                if (mouseEvent.getClickCount() >= 2) {
                    editRecord();
                }
            }
        });
        table.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent keyEvent) {
                if (table.getSelectedIndex() < 0) {
                    return;
                }
                switch (keyEvent.getKeyChar()) {
                    case KeyEvent.VK_DELETE:
                        deleteRecord();
                        break;
                    case KeyEvent.VK_ENTER:
                        editRecord();
                }
            }
        });
        rowDialog.addWindowListener(new WindowAdapter() {
            @Override
            public void windowDeactivated(WindowEvent windowEvent) {
                if (table.isVisible()) {
                    table.requestFocus();
                }
            }
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(createButton);
        buttonPanel.add(editButton);
        buttonPanel.add(deleteButton);
        buttonPanel.add(findButton);
        buttonPanel.add(showAllButton);
        buttonPanel.add(reconnectButton);
        buttonPanel.add(optionsButton);

        JScrollPane sp = new JScrollPane(table);
        JPanel contentPane = new JPanel();
        contentPane.setDoubleBuffered(true);
        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));

        contentPane.add(buttonPanel);
        contentPane.add(sp);
        this.setContentPane(contentPane);
        this.setSize(dim);
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent windowEvent) {
                new Thread() {
                    public void run() {
                        service.init();
                    }
                }.start();
            }

            @Override
            public void windowClosed(WindowEvent e) {
                service.shutdown();
            }
        });
    }

    private void deleteRecord() {
        service.delete();
    }

    private void editRecord() {
        disable(editButton, deleteButton, createButton, findButton, showAllButton, table);
        rowDialog.edit();
    }

    /**
     * updates the current view componen state
     * @param observable event source
     * @param o event object sent to observers
     */
    public void update(Observable observable, Object o) {
        if (o == null || !(o instanceof Notification)) {
            return;
        }
        final Notification n = (Notification) o;
        final JFrame frame = this;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (n.getEvent() instanceof ServiceEvent) {
                    ServiceEvent a = (ServiceEvent) n.getEvent();
                    switch (a) {
                        case DELETING:
                            disable(deleteButton);
                            break;
                        case LOCK_CANCELLED:
                        case UPDATED:
                        case UNLOCKED:
                            enable(editButton, deleteButton, createButton, findButton, showAllButton, table);
                            break;
                        case INITING:
                            disable(reconnectButton, createButton, deleteButton, showAllButton, findButton, editButton);
                            break;
                        case INIT_ERROR:
                            enable(reconnectButton);
                        case ROW_REMOVED:
                            SwingUtils.showError(frame, n.getMessage());
                            break;
                        case INITED:
                            enable(showAllButton, createButton, findButton, reconnectButton);
                            break;
                        case ERROR:
                            SwingUtils.showError(frame, n.getMessage());
                            if (service.isActive()) {
                                enable(createButton, table);
                                if (table.getSelectedIndex() >= 0) {
                                    enable(editButton, deleteButton);
                                }
                            }
                            break;
                    }
                }
            }
        });
    }

    /**
     * called whenever the value of the selection changes
     * @param e the event that characterizes the change
     */
    public void valueChanged(ListSelectionEvent e) {
        if (e.getValueIsAdjusting()) {
            return;
        }
        ListSelectionModel lsm = (ListSelectionModel) e.getSource();
        if (!lsm.isSelectionEmpty()) {
            service.select(lsm.getMinSelectionIndex());
            enable(deleteButton, editButton);
        } else {
            service.select(-1);
            disable(deleteButton, editButton);
        }
    }
}
